extends IBasicComponent


class_name IDragController
"""
数据拖拽控制
"""


## 全局的拖拽标记
class Shared:
    var is_dragging: bool = false
    var from: Control = null
    var to: Control = null
    var ui: Control = null
    var data: Variant = null

    func init(wrapper: Control, drag_data: Variant, drag_ui: Control) -> void:
        is_dragging = true
        from = wrapper
        to = wrapper
        data = drag_data
        ui = drag_ui
        from.accept_event()

    func clear() -> void:
        is_dragging = false
        from.accept_event()
        from = null
        to = null
        data = null
        if ui:
            ui.queue_free()
        ui = null


## 拖拽预览时与鼠标的偏移
@export var drag_preview_offset: Vector2 = Vector2(1, 1)
## 拖动鼠标按键
@export var drag_button: MouseButton = MOUSE_BUTTON_LEFT
## 放置鼠标按键
@export var drop_button: MouseButton = MOUSE_BUTTON_LEFT


var shared: Shared = Shared.new()


func is_start(event: InputEvent) -> bool:
    return NodeHelper.is_mouse_pressed(event, drag_button)

func is_stop(event: InputEvent) -> bool:
    if drop_button == drag_button:
        return NodeHelper.is_mouse_released(event, drop_button)
    return NodeHelper.is_mouse_pressed(event, drop_button)

func ready_to_drag(wrapper: Control) -> bool:
    var data: Variant = drag(wrapper)
    if data:
        shared.init(wrapper, data, get_drag_preview(wrapper, data))
        return true
    return false

func on_mouse_dragging(event: InputEvent) -> void:
    if not shared.is_dragging:
        return
    if event is InputEventMouseMotion:
        shared.ui.global_position = shared.ui.get_global_mouse_position() + drag_preview_offset
    if is_stop(event):
        if shared.to:
            shared.to.accept_event()
        # 鼠标未移出
        if shared.from == shared.to:
            cancel_drop(shared.from, shared.data)
            shared.clear()
            return
        if shared.to and can_drop(shared.to, shared.data):
            drop(shared.from, shared.to, shared.data)
        else:
            drop_to_floor(shared.from, shared.data)
        shared.clear()

func _unhandled_input(event: InputEvent) -> void:
    on_mouse_dragging(event)

func drag(drag_from: Control) -> Variant:
    return null

func get_drag_preview(drag_from: Control, data: Variant) -> Control:
    return null

func can_drop(drag_from: Control, data: Variant) -> bool:
    return false

func drop(drag_from: Control, drag_to: Control, data: Variant) -> void:
    pass

func drop_to_floor(drag_from: Control, data: Variant) -> void:
    pass

func cancel_drop(drag_from: Control, data: Variant) -> void:
    pass
